--[[------------------------------------------------------------------
--  $id$
--
--  DongleHelloWorld is a simple library to illustate the overall
--  coding style for all Dongle core libraries.  It will illustrate
--  how to act as a standalone library, as well as registering it's
--  API with the Dongle core.
--
--  Copyright 2007 by James N. Whitehead II
------------------------------------------------------------------]]--

-- Virtually all libraries will require DongleStub for versioning
-- These are the major and minor version declarations for that stub

local major = "DongleHelloWorld-2.0"
local minor = tonumber(("$Revision$"):match("(%d+)")) or 1

-- To avoid duplicate library definitions, we need to wrap our code
-- in a conditional.  These can't be done as a simple return, since
-- libraies will be packaged with other libraries in the same file

assert(DongleStub, ("%s requires DongleStub."):format(major))

if DongleStub:IsNewerVersion(major, minor) then
	
	-- The library is fully defined here, as a local.  To avoid
	-- extremly long function names, and since libraies are
	-- essentially nameless, I name the library local "lib".

	-- All data should be kept in a single table, which is then
	-- referenced locally by the code.  I call this single data
	-- repository "registry"

	-- In this case, we don't have any data that needs to be stored
	-- other than the list of clients the library has.  This data
	-- needs to be tracked in order to properly update on upgrade

	-- We need to have the registry somewhere accesible to other addons
	-- mainly so we don't have to have a rigid upgrade procedure.

	local lib = {
		registry = {
			embedClients = {},
		}
	}

	-- Create local variables due to scoping.  These will actually
	-- be initialized in the Activate function, with the values
	-- from registry and registry.embedClients.

	local registry, embedClients

	-- Define the external API here, so we can export it to another
	-- namespace, or register it with the Dongle core.

	local external_api = {"HelloWorld",}

	-- Define the :Embed() method, which will be used to pull the
	-- exported API into a new namespace.  This method will NOT
	-- be used for the DongleCore registration.

	function lib:Embed(namespace)
		table.insert(embedClients, namespace)
		for idx,method in pairs(external_api) do
			namespace[method] = self[method]
		end
	end

	-- Create the actual API function here.  In this case, this is
	-- a simple function which will return the string "Hello World!"
	-- in a given language.

	local L = {
		["enUS"] = "Hello World!",
		["frFR"] = "Bonjour Monde !",
		["deDE"] = "Hallo Welt!",
	}

	function lib:HelloWorld(locale)
		if type(locale) ~= "string" then
			-- This error is thrown at level 2, so it appears correctly
			-- as an error in the call to HelloWorld rather than the
			-- HelloWorld function itself.

			-- Level 0: The error() function itself
			-- Level 1: This HelloWorld function
			-- Level 2: The calling line

			error("Locale supplied to HelloWorld must be a string", 2)
		end

		return L[locale] or L.enUS
	end

	-- Define a DongleCoreRegister() method which will be used to 
	-- hook into DongleCore if it exists, otherwise it will define
	-- event handlers to accomplish this in a delayed manner

	-- This signifies the specific version of DongleCore we expect
	local dongle_major = "DongleCore-2.0"

	-- This is a simple event handler function.  This will be set on a
	-- frame which is only registered for ADDON_LOADED.  The sole purpose
	-- of this function is to catch situations where this library is
	-- loaded prior to the DongleCore core.  We check each ADDON_LOADED
	-- to see if DongleCore has arrived, and if so, we register our API.

	local function DongleCoreOnEvent(frame, event, addon)
		if DongleStub:HasVersion(dongle_major) then
			frame:UnregisterEvent("ADDON_LOADED")
			registry.coreframe = nil
			DongleCore:RegisterCoreAPI(major, external_api)
		end
	end

	function lib:DongleCoreRegister()
		if DongleStub:HasVersion(dongle_major) then
			-- There is a version currently registered with DongleStub
			-- We need to call the :RegisterCoreAPI() function
			
			local DongleCore = DongleStub("DongleCore-2.0")
			DongleCore:RegisterCoreAPI(major, external_api)
		else
			-- Use a simple frame to register for ADDON_LOADED to watch
			-- a delayed entry of DongleCore.
			if not registry.coreframe then
				local frame = CreateFrame("Frame")
				frame:RegisterEvent("ADDON_LOADED")
				registry.coreframe = frame
			end

			registry.coreframe:SetScript("OnEvent", DongleCoreOnEvent)
		end
	end

	-- Define the GetVersion() method, which is used consistently in 
	-- all DongleStub objects to get the proper major,minor versions
	-- of the library.

	function lib:GetVersion() 
		return major,minor
	end

	-- Here we define the Activate and Deactivate functions to interface
	-- with DongleStub.  The activate function is passed the NEW instance
	-- and the OLD instance (when upgrading), or just the NEW instance 
	-- when its a new major version.  The deactivate function is passed
	-- the OLD instance, and the NEW instance in all cases.

	-- I define these functions to be local, but they could be placed in
	-- the lib namespace.  I do this for clarify in-game.

	local function Activate(new, old)
		-- If there is an old instance, we need to pull in the registry
		-- Do this conditionally, in case the old version is lacking
		-- a registry for some reason

		if old then
			new.registry = old.registry or new.registry
		end

		-- Set the local variables for this file
		registry = new.registry
		embedClients = registry.embedClients

		-- Call the :DongleCoreRegister() method, which will handle
		-- any hooks into DongleCore.  This function will correctly
		-- work on an upgrade, since it uses registry.coreframe.
		new:DongleCoreRegister()
	end

	local function Deactivate(old, new)
		-- There should be no deactivation necessary here
	end

	-- Register this library instance with DongleStub.  Because DongleStub
	-- re-uses tables in order to preserve references, we may need to re-bind
	-- our library.

	lib = DongleStub:Register(lib, Activate, Deactivate)
end
